<?php

class SP_Uri{
    var $uri_string = FALSE;
    var $segments   = Array();
    var $rsegments  = Array();
    var $routes     = Array();
    var $class      = '';
    var $method     = 'index';
    var $default_controller;

    function SP_Uri(){
        $this->config =& Loader::config();
        $this->_set_routing();
    }

    function _set_routing(){

        @include(APPBASE.'Config/routes.php');
        $this->routes = ( ! isset($ROUTE) OR ! is_array($ROUTE)) ? array() : $ROUTE;
        unset($ROUTE);

        $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']);

        $this->_fetch_uri_string();
        if ($this->uri_string == ''){
            if ($this->default_controller === FALSE){
                showError(__T('Unable to determine what should be displayed. A default route has not been specified in the routing file.'));
            }

            if(!file_exists(APPBASE.'Controllers/'.$this->default_controller.'.php')){
                showError(__T('Unable to load your default controller.  Please make sure the controller specified in your Routes.php file is valid.'));
            }

            $this->class = $this->default_controller;
            $this->method = 'index';

            $this->_reindex_segments();
            return;
        }

        $this->_remove_url_suffix();
        $this->_explode_segments();
        $this->_parse_routes();
        $this->_reindex_segments();
    }

    function _parse_routes(){
        // Do we even have any custom routing to deal with?
        // There is a default scaffolding trigger, so we'll look just for 1
        if (count($this->routes) == 1)
        {
            $this->_set_request($this->segments);
            return;
        }

        // Turn the segment array into a URI string
        $uri = implode('/', $this->segments);

        // Is there a literal match?  If so we're done
        if (isset($this->routes[$uri]))
        {
            $this->_set_request(explode('/', $this->routes[$uri]));
            return;
        }

        // Loop through the route array looking for wild-cards
        foreach ($this->routes as $key => $val)
        {
            // Convert wild-cards to RegEx
            $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));

            // Does the RegEx match?
            if (preg_match('#^'.$key.'$#', $uri))
            {
                // Do we have a back-reference?
                if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
                {
                    $val = preg_replace('#^'.$key.'$#', $val, $uri);
                }

                $this->_set_request(explode('/', $val));
                return;
            }
        }

        // If we got this far it means we didn't encounter a
        // matching route so we'll set the site default route
        $this->_set_request($this->segments);
    }

    function _set_request($segments = array()){
        //$segments = $this->_validate_request($segments);
        if (count($segments) == 0)
        {
            return;
        }

        $this->class = $segments[0];

        if (isset($segments[1])){
                // A standard method request
                $this->method = $segments[1];
        }else{
            // This lets the "routed" segment array identify that the default
            // index method is being used.
            $segments[1] = 'index';
        }

        // Update our "routed" segment array to contain the segments.
        // Note: If there is no custom routing, this array will be
        // identical to $this->uri->segments
        $this->rsegments = $segments;
    }

    function _fetch_uri_string(){
        if (strtoupper($this->config['uri_protocol']) == 'AUTO'){
            // Is there a PATH_INFO variable?
            // Note: some servers seem to have trouble with getenv() so we'll test it two ways
            $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
            if (trim($path, '/') != '' && $path != "/".SELF){
                $this->uri_string = $path;
                return;
            }

            // No PATH_INFO?... What about QUERY_STRING?
            $path =  (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
            if (trim($path, '/') != ''){
                $uri_arr = explode('&',str_replace('&amp;','&',$path));
                $this->uri_string = $uri_arr[0];
                return;
            }

            // No QUERY_STRING?... Maybe the ORIG_PATH_INFO variable exists?
            $path = (isset($_SERVER['ORIG_PATH_INFO'])) ? $_SERVER['ORIG_PATH_INFO'] : @getenv('ORIG_PATH_INFO');
            if (trim($path, '/') != '' && $path != "/".SELF){
                // remove path and script information so we have good URI data
                $this->uri_string = str_replace($_SERVER['SCRIPT_NAME'], '', $path);
                return;
            }

            // We've exhausted all our options...
            $this->uri_string = '';
        }
        else{
            $uri = strtoupper($this->config['uri_protocol']);

            if ($uri == 'REQUEST_URI'){
                $this->uri_string = $this->_parse_request_uri();
                return;
            }elseif ($uri == 'PATH_INFO'){
                $this->uri_string = $this->_parse_path_info();
            }elseif ($uri == 'QUERY_STRING'){
                $path =  (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
                $uri_arr = explode('&',str_replace('&amp;','&',$path));
                $this->uri_string = $uri_arr[0];
            }else{
                $this->uri_string = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
            }
        }

        // If the URI contains only a slash we'll kill it
        if ($this->uri_string == '/'){
            $this->uri_string = '';
        }
    }

    // --------------------------------------------------------------------
    function _parse_path_info(){
        if ( ! isset($_SERVER['PATH_INFO']) || $_SERVER['PATH_INFO'] == ''){
            $strlen = strlen(_getScriptPath());
            $totallen = strlen($_SERVER['PHP_SELF']);
            return substr($_SERVER['PHP_SELF'],$strlen,$totallen);
        }else{
            return $_SERVER['PATH_INFO'];
        }
    }
    /**
     * Parse the REQUEST_URI
     *
     * @access    private
     * @return    string
     */
    function _parse_request_uri(){
        if ( ! isset($_SERVER['REQUEST_URI']) || $_SERVER['REQUEST_URI'] == ''){
            return '';
        }

        $request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI']));

        if ($request_uri == '' || $request_uri == SELF){
            return '';
        }

        $fc_path = FCPATH;
        $spos = strpos($request_uri, '?');
        if ($spos !== FALSE){
            $fc_path .= '?';
            $request_uri = substr($request_uri,0,$spos);
        }

        $fc_path = str_replace("\\", "/", $fc_path);
        $parsed_uri = explode("/", $request_uri);

        $i = 0;
        foreach(explode("/", $fc_path) as $segment){
            if (isset($parsed_uri[$i]) && $segment == $parsed_uri[$i]){
                $i++;
            }
        }

        $parsed_uri = implode("/", array_slice($parsed_uri, $i));

        if ($parsed_uri != ''){
            $parsed_uri = '/'.$parsed_uri;
        }

        return $parsed_uri;
    }

    function _filter_uri($str){
        if ($str != ''){
            if ( ! preg_match("|^[a-z 0-9~%.:_\-]+$|i", urlencode($str))){
                showError(__T('The URI you submitted has disallowed characters.'));
            }
        }

        // Convert programatic characters to entities
        $bad    = array('$',         '(',         ')',         '%28',         '%29');
        $good    = array('&#36;',    '&#40;',    '&#41;',    '&#40;',    '&#41;');

        return str_replace($bad, $good, $str);
    }

    function _explode_segments(){
        foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val){
            // Filter segments for security
            $val = trim($this->_filter_uri($val));

            if ($val != ''){
                $this->segments[] = $val;
            }
        }
    }
    function _reindex_segments()
    {
        array_unshift($this->segments, NULL);
        array_unshift($this->rsegments, NULL);
        unset($this->segments[0]);
        unset($this->rsegments[0]);
    }
    function _remove_url_suffix(){
        if  ($this->config['url_suffix'] != ""){
            $this->uri_string = preg_replace("|".preg_quote($this->config['url_suffix'])."$|", "", $this->uri_string);
        }
    }

    function segment($n, $no_result = FALSE){
        return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
    }

    function rsegment($n, $no_result = FALSE){
        return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
    }
    function getRsegments(){
        return $this->rsegments;
    }
    function getSegments(){
        return $this->segments;
    }

    function getClass(){
        return $this->class;
    }

    function getMethod(){
        return $this->method;
    }
}
